package com.puzzlebazar.server;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Blob;
import com.puzzlebazar.client.puzzle.model.History;
import com.puzzlebazar.client.puzzleinfo.HistoryInfo;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class HistoryInfoJdo {

	@PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String key;

	@Persistent
	private String puzzleInfoKey = null; // A key into HistoryInfoJdo
	@Persistent
	private Date dateEdited = null;
	@Persistent
	private Date dateCompleted = null;

	@Persistent
	private Blob historyModel = null;
	@Persistent
	private String authorEmail = null; // A key into UserInfoJdo
	

    /**
     * @param destination The HistoryInfo object to populate with this object content
     * @param loadModel True if the historyModel should be loaded. If false, 
     *                  destination.historyModel will not be modified
     */
    public void to( HistoryInfo destination, boolean loadModel ) {
    	destination.setKey(key);
    	destination.setPuzzleInfoKey(puzzleInfoKey);
    	destination.setDateEdited( dateEdited );
    	destination.setDateCompleted( dateCompleted );
    	destination.setAuthorEmail( authorEmail );
    	destination.setAuthorUsername( authorEmail ); // TODO wrong username
    	if( loadModel ) {
			destination.setHistoryModel( getHistoryModel() );
    	}
    }

    /**
     * Create a new history based on the information passed
     * 
     * @param source The object containing all the information for the newly created history
     *               The following fields are disregarded:
     *                  key
     *                  dateEdited
     *                  datecompleted
     */
    public void create( HistoryInfo source ) throws Exception {
    	puzzleInfoKey = source.getPuzzleInfoKey();
    	dateEdited = new Date();
    	dateCompleted = null;
    	historyModel = null;
    	authorEmail = source.getAuthorEmail();
    }
	

	/**
	 * Attach the passed model to the current history info.
	 * 
	 * @param model The model to attach
	 */
	public void attachHistoryModel(History model) {
		assert( model != null );
    	setHistoryModel(model);
	}
	
	
    /**
     * @return A newly created History object corredponding to the one attached to this JDO, null if an error occured
     */
    private History getHistoryModel() {
    	if( historyModel == null ) return null;
    	History result = null;
		try {
	    	ByteArrayInputStream modelByteStream = new ByteArrayInputStream(historyModel.getBytes());
	    	ObjectInputStream modelStream = new ObjectInputStream(modelByteStream);
	    	result = (History)modelStream.readObject();
	    	modelStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
     * @param puzzleModel The puzzle model to attach to this JDO
     */
    private void setHistoryModel(History historyModel) {
		try {
			ByteArrayOutputStream modelByteStream = new ByteArrayOutputStream(512);
	    	ObjectOutputStream modelStream = new ObjectOutputStream(modelByteStream);
	    	modelStream.writeObject( historyModel );
	    	this.historyModel = new Blob(modelByteStream.toByteArray());
	    	modelStream.close();
		} catch (Exception e) {
			this.historyModel = null;
			e.printStackTrace();
		}
	}
    

	/**
	 * Set the edition date 
	 *
	 * @param date The date to set, null to reset
	 */
	public void setDateEdited( Date date ) {
		dateEdited = date;
	}

	/**
	 * Set the completion date 
	 *
	 * @param date The date to set, null to reset
	 */
	public void setDateCompleted( Date date ) {
		dateCompleted = date;
	}

	/**
	 * @return The key associated with this hidotry
	 */
	public String getKey() {
		return key;
	}    
    
}
